{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# Redis入门——字符串、列表与集合\n",
    "![](https://kingname-1257411235.cos.ap-chengdu.myqcloud.com/2019-02-23-13-22-19.png)\n"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 使用Python连接Redis\n",
    "\n",
    "### 基本语法\n",
    "\n",
    "```\n",
    "import redis\n",
    "client = redis.Redis()\n",
    "```"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 1,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
    "import redis\n",
    "\n",
    "client = redis.Redis()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 字符串\n",
    "\n",
    "### 基本语法\n",
    "\n",
    "```\n",
    "# 向字符串中写入数据\n",
    "client.set(key, value)\n",
    "\n",
    "# 从字符串中读取数据\n",
    "client.get(key)\n",
    "\n",
    "# 设置字符串的过期时间\n",
    "client.set(key, value, ex=30)  # ex的单位为秒\n",
    "\n",
    "# 如果字符串的值为数字，那么可以自增和自减\n",
    "client.incr(key, n)  # 自增n\n",
    "client.decr(key, n)  # 自减n\n",
    "```"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 向Redis中添加一个字符串，Key为kingname，value为现在时间"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "True"
      ]
     },
     "execution_count": 2,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "import datetime\n",
    "now = datetime.datetime.now().strftime('%Y-%m-%d %H:%M:%S')\n",
    "client.set('kingname', now)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 读取Redis中，Key为kingname的字符串的值"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "读取下来的数据，它的类型为：<class 'bytes'>\n",
      "字符串里面的值为：2019-02-25 21:13:13\n"
     ]
    }
   ],
   "source": [
    "target_time = client.get('kingname')\n",
    "\n",
    "# 我们来看看读取下来的数据是什么类型的\n",
    "print(f'读取下来的数据，它的类型为：{type(target_time)}')\n",
    "\n",
    "# 把数据类型转化为字符串\n",
    "\n",
    "target_time_str = target_time.decode()\n",
    "\n",
    "print(f'字符串里面的值为：{target_time_str}')"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 如果读取的字符串Key不存在，会怎么样？\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "读取不存在的值，返回的结果是：None\n"
     ]
    }
   ],
   "source": [
    "not_exists_value = client.get('Iamhero')\n",
    "\n",
    "print(f'读取不存在的值，返回的结果是：{not_exists_value}')"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "metadata": {},
   "outputs": [
    {
     "ename": "AttributeError",
     "evalue": "'NoneType' object has no attribute 'decode'",
     "output_type": "error",
     "traceback": [
      "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m",
      "\u001b[0;31mAttributeError\u001b[0m                            Traceback (most recent call last)",
      "\u001b[0;32m<ipython-input-5-4affe285d63d>\u001b[0m in \u001b[0;36m<module>\u001b[0;34m()\u001b[0m\n\u001b[1;32m      1\u001b[0m \u001b[0;31m# 必定报错\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m----> 2\u001b[0;31m \u001b[0mnot_exists_value\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mdecode\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m",
      "\u001b[0;31mAttributeError\u001b[0m: 'NoneType' object has no attribute 'decode'"
     ]
    }
   ],
   "source": [
    "# 必定报错\n",
    "not_exists_value.decode()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 为Key设置过期时间\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "插入以后立刻读取，结果是：2019-02-25 21:13:25\n",
      "30秒以后再来读一下，值为：None\n"
     ]
    }
   ],
   "source": [
    "import time\n",
    "now = datetime.datetime.now().strftime('%Y-%m-%d %H:%M:%S')\n",
    "client.set('kingname', now, ex=30) \n",
    "\n",
    "value = client.get('kingname').decode()\n",
    "print(f'插入以后立刻读取，结果是：{value}')\n",
    "time.sleep(31)\n",
    "value = client.get('kingname')  # 注意，这个地方不要decode()\n",
    "print(f'30秒以后再来读一下，值为：{value}')  \n"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# 对于值为数字的字符串，自己增"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "当你把数字写进Redis再读出来的时候，你会发现它的类型变成了：<class 'str'>\n"
     ]
    }
   ],
   "source": [
    "client.set('num_value', 10)  # 设置一个值为10的字符串，key为num_value\n",
    "value = client.get('num_value').decode()\n",
    "print(f'当你把数字写进Redis再读出来的时候，你会发现它的类型变成了：{type(value)}')"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 8,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "再次读取，发现值变成了：11\n"
     ]
    }
   ],
   "source": [
    "client.incr('num_value')\n",
    "value = client.get('num_value').decode()\n",
    "print(f'再次读取，发现值变成了：{value}')"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 9,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "再次读取，发现值变成了：21\n"
     ]
    }
   ],
   "source": [
    "client.incr('num_value', 10)\n",
    "value = client.get('num_value').decode()\n",
    "print(f'再次读取，发现值变成了：{value}')"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 对于值为数字的字符串，自减"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 10,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "再次读取，发现值变成了：20\n"
     ]
    }
   ],
   "source": [
    "client.decr('num_value')\n",
    "value = client.get('num_value').decode()\n",
    "print(f'再次读取，发现值变成了：{value}')"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 11,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "再次读取，发现值变成了：10\n"
     ]
    }
   ],
   "source": [
    "client.decr('num_value', 10)\n",
    "value = client.get('num_value').decode()\n",
    "print(f'再次读取，发现值变成了：{value}')"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# Redis入门——字符串、列表与集合\n",
    "![](https://kingname-1257411235.cos.ap-chengdu.myqcloud.com/2019-02-23-13-22-19.png)\n"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Redis列表的基本操作\n",
    "\n",
    "### 基本语法\n",
    "\n",
    "```\n",
    "# 向列表左侧添加一个值\n",
    "client.lpush(key, 'value1')\n",
    "# 向列表左侧添加很多个值\n",
    "client.lpush(key, 'value1', 'value2')\n",
    "\n",
    "#向列表右侧添加一个或者多个值\n",
    "client.rpush(key, 'value1', 'value2')\n",
    "\n",
    "#从列表左侧弹出一个值\n",
    "client.lpop(key)\n",
    "\n",
    "#从列表右侧弹出一个值\n",
    "client.rpop(key)\n",
    "\n",
    "#获得列表的长度\n",
    "client.llen(key)\n",
    "\n",
    "# 获得列表里面的值，但是不删除他们\n",
    "client.lrange(key, 1, 5)\n",
    "```"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 向列表中添加数据"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 12,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "1"
      ]
     },
     "execution_count": 12,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "# 添加一条数据\n",
    "client.lpush('users', 'kingname')"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 13,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "4"
      ]
     },
     "execution_count": 13,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "# 添加多条\n",
    "client.lpush('users', 'one', 'two', 'three')"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 14,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "8"
      ]
     },
     "execution_count": 14,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "# 另一种方式添加多条数据\n",
    "data = ['four', 5, 'VI', '七']\n",
    "client.lpush('users', *data)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 15,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "9"
      ]
     },
     "execution_count": 15,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "# 向右侧添加一条数据\n",
    "client.rpush('users', 8)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 16,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "12"
      ]
     },
     "execution_count": 16,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "# 向右侧添加多条数据\n",
    "\n",
    "client.rpush('users', 9, 10, 11)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 从列表中弹出数据"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 17,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "弹出的数据，类型为：<class 'bytes'>\n",
      "弹出的数据为：七\n"
     ]
    }
   ],
   "source": [
    "# 从左侧弹出数据\n",
    "\n",
    "data = client.lpop('users')\n",
    "\n",
    "print(f'弹出的数据，类型为：{type(data)}')\n",
    "data_str = data.decode()\n",
    "print(f'弹出的数据为：{data_str}')"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 18,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "弹出的数据为：11\n"
     ]
    }
   ],
   "source": [
    "# 从列表右侧弹出数据\n",
    "\n",
    "data = client.rpop('users')\n",
    "\n",
    "data_str = data.decode()\n",
    "print(f'弹出的数据为：{data_str}')"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 获取列表长度\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 19,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "当前列表里面有10条数据\n"
     ]
    }
   ],
   "source": [
    "length = client.llen('users')\n",
    "print(f'当前列表里面有{length}条数据')"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 从列表里面获取数据但不删除\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 20,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "直接获取的数据为：[b'VI', b'5', b'four', b'three']\n",
      "VI\n",
      "5\n",
      "four\n",
      "three\n"
     ]
    }
   ],
   "source": [
    "# 获取前4条数据\n",
    "first_three_data = client.lrange('users', 0, 3)\n",
    "print(f'直接获取的数据为：{first_three_data}')\n",
    "\n",
    "for data in first_three_data:\n",
    "    print(data.decode())"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 21,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "VI\n",
      "5\n",
      "four\n",
      "three\n",
      "two\n",
      "one\n",
      "kingname\n",
      "8\n",
      "9\n",
      "10\n"
     ]
    }
   ],
   "source": [
    "# 获取所有数据\n",
    "\n",
    "all_data = client.lrange('users', 0, -1)\n",
    "\n",
    "for data in all_data:\n",
    "    print(data.decode())"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 22,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "two\n",
      "one\n",
      "kingname\n",
      "8\n",
      "9\n"
     ]
    }
   ],
   "source": [
    "# 获取倒数第6至倒数第2条数据\n",
    "\n",
    "last_few_data = client.lrange('users', -6, -2)\n",
    "for data in last_few_data:\n",
    "    print(data.decode())"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "![读者交流QQ群](https://kingname-1257411235.cos.ap-chengdu.myqcloud.com/2019-02-16-09-59-56.png)\n",
    "![微信公众号](https://kingname-1257411235.cos.ap-chengdu.myqcloud.com/wechatplatform.jpg)\n",
    "![](https://kingname-1257411235.cos.ap-chengdu.myqcloud.com/2019-02-23-13-22-45.png)\n"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": []
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 集合的基本操作\n",
    "\n",
    "```\n",
    "# 往集合中添加数据\n",
    "client.sadd(key, 'value1', 'value2')\n",
    "\n",
    "# 列出集合中所有数据（慎用）\n",
    "client.smembers(key)\n",
    "\n",
    "\n",
    "# 从集合中弹出数据\n",
    "client.spop(key)\n",
    "\n",
    "# 判断value是否在集合中\n",
    "client.sismember(key, 'value')\n",
    "\n",
    "# 两个集合做交集\n",
    "client.sinter(key1, key2)\n",
    "\n",
    "# 两个集合做并集\n",
    "client.sunion(key1, key2)\n",
    "\n",
    "# 两个集合做差集\n",
    "client.sdiff(key1, key2)\n",
    "```"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 向集合中添加数据"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 26,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "添加数据的返回结果：1\n",
      "返回数据的类型：<class 'int'>\n"
     ]
    }
   ],
   "source": [
    "# 添加一条数据\n",
    "result = client.sadd('account', 'kingname')\n",
    "print(f'添加数据的返回结果：{result}')\n",
    "print(f'返回数据的类型：{type(result)}')"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 27,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "添加数据的返回结果：3\n"
     ]
    }
   ],
   "source": [
    "# 通过多个参数添加多条数据\n",
    "result = client.sadd('account', '王小二', '张小三', '李小四')\n",
    "print(f'添加数据的返回结果：{result}')"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 28,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "添加数据的返回结果：3\n"
     ]
    }
   ],
   "source": [
    "# 使用列表添加多个数据\n",
    "\n",
    "account = ['Bob', 'Alice', 'Dilen']\n",
    "result = client.sadd('account', *account)\n",
    "print(f'添加数据的返回结果：{result}')"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 29,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "添加数据的返回结果：0\n"
     ]
    }
   ],
   "source": [
    "# 添加一条重复数据\n",
    "\n",
    "result = client.sadd('account', 'kingname')\n",
    "print(f'添加数据的返回结果：{result}')"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 列出集合中的所有数据"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 30,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "返回的数据: {b'Bob', b'Alice', b'kingname', b'\\xe7\\x8e\\x8b\\xe5\\xb0\\x8f\\xe4\\xba\\x8c', b'\\xe6\\x9d\\x8e\\xe5\\xb0\\x8f\\xe5\\x9b\\x9b', b'Dilen', b'\\xe5\\xbc\\xa0\\xe5\\xb0\\x8f\\xe4\\xb8\\x89'}\n",
      "Bob\n",
      "Alice\n",
      "kingname\n",
      "王小二\n",
      "李小四\n",
      "Dilen\n",
      "张小三\n"
     ]
    }
   ],
   "source": [
    "# 列出集合中的所有数据\n",
    "\n",
    "all_data = client.smembers('account')\n",
    "print(f'返回的数据: {all_data}')\n",
    "for data in all_data:\n",
    "    print(data.decode())"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 从集合中弹出数据"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 31,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "被弹出的数据类型为：<class 'bytes'>\n",
      "被弹出的数据为：王小二\n"
     ]
    }
   ],
   "source": [
    "# 从集合中弹出数据\n",
    "\n",
    "data = client.spop('account')\n",
    "print(f'被弹出的数据类型为：{type(data)}')\n",
    "print(f'被弹出的数据为：{data.decode()}')"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 判断一条数据是否在集合中"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 32,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "如果数据在集合中，返回：True\n"
     ]
    }
   ],
   "source": [
    "# 数据在集合中\n",
    "exists = client.sismember('account', 'kingname')\n",
    "print(f'如果数据在集合中，返回：{exists}')\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 33,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "如果数据不在集合中，返回：False\n"
     ]
    }
   ],
   "source": [
    "# 数据不在集合中\n",
    "not_exists = client.sismember('account', 'asdfasdfadf')\n",
    "print(f'如果数据不在集合中，返回：{not_exists}')"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 交集、并集、差集"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 34,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "4"
      ]
     },
     "execution_count": 34,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "# 生成测试数据\n",
    "\n",
    "data_1 = [1, 2, 3, 4, 5]\n",
    "data_2 = [4, 5, 6, 7]\n",
    "client.sadd('data_1', *data_1)\n",
    "client.sadd('data_2', *data_2)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 35,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "{b'4', b'5'}"
      ]
     },
     "execution_count": 35,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "# 交集\n",
    "\n",
    "client.sinter('data_1', 'data_2')"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 37,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "{b'1', b'2', b'3', b'4', b'5', b'6', b'7'}"
      ]
     },
     "execution_count": 37,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "# 并集\n",
    "client.sunion('data_1', 'data_2')"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 38,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "{b'1', b'2', b'3'}"
      ]
     },
     "execution_count": 38,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "# 差集 data_1 - data_2\n",
    "client.sdiff('data_1', 'data_2')"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 39,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "{b'6', b'7'}"
      ]
     },
     "execution_count": 39,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "# 差集 data_2 - data_1\n",
    "client.sdiff('data_2', 'data_1')"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "\n"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "collapsed": true
   },
   "source": [
    "# Redis入门——字符串、列表与集合的使用场景举例\n",
    "![](https://kingname-1257411235.cos.ap-chengdu.myqcloud.com/2019-03-03-16-52-34.png)\n"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 字符串——简单的映射关系\n",
    "\n",
    "> 注意：绝对不能滥用字符串！！！"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "metadata": {},
   "outputs": [],
   "source": [
    "# 生成初始数据\n",
    "import redis\n",
    "\n",
    "data = {\n",
    "    1001: '王一',\n",
    "    1002: '马二',\n",
    "    1003: '张三',\n",
    "    1004: '李四',\n",
    "    1005: '赵五',\n",
    "    1006: '朱六',\n",
    "    1007: '卓七',\n",
    "    1008: '钱八',\n",
    "    1009: '孙九',\n",
    "    1010: '周十'\n",
    "}\n",
    "client = redis.Redis()\n",
    "for num, name in data.items():\n",
    "    client.set(num, name)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "ID为1006的人，它的名字为：朱六\n"
     ]
    }
   ],
   "source": [
    "# 查询ID为1006的人，它的名字是什么？\n",
    "\n",
    "name = client.get(1006)\n",
    "print(f'ID为1006的人，它的名字为：{name.decode()}')"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 列表——用来作为队列"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
    "import random\n",
    "def send_sms(phone_number):\n",
    "    print(f'开始给{phone_number}发送短信，整个过程大概1-2秒钟')\n",
    "    time.sleep(random.randint(1, 2))\n",
    "    return random.randint(0, 9) % 2 == 0  # 在0到9之间随机生成一个整数，偶数表示发送成功\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
    "import time\n",
    "import json\n",
    "def read_wait_queue():\n",
    "    while True:\n",
    "        phone_info_bytes = client.lpop('phone_queue')\n",
    "        if not phone_info_bytes:\n",
    "            print('队列中没有短信，等待')\n",
    "            time.sleep(10)\n",
    "            continue\n",
    "\n",
    "        phone_info = json.loads(phone_info_bytes.decode())\n",
    "        retry_times = phone_info.get('retry_times', 0)\n",
    "        phone_number = phone_info['phone_number']\n",
    "        result = send_sms(phone_number)\n",
    "        if result:\n",
    "            print(f'手机号：{phone_number} 短信发送成功！')\n",
    "            continue\n",
    "        print(f'手机号：{phone_number} 短信发送失败，等待重试！')\n",
    "\n",
    "        if retry_times >= 3:\n",
    "            print(f'重试超过3次，放弃手机号：{phone_number}')\n",
    "            continue\n",
    "        next_phone_info = {'phone_number': phone_number, 'retry_times': retry_times + 1}\n",
    "        client.rpush('phone_queue', json.dumps(next_phone_info))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "队列中没有短信，等待\n",
      "队列中没有短信，等待\n",
      "开始给12345678发送短信，整个过程大概1-2秒钟\n",
      "手机号：12345678 短信发送成功！\n",
      "队列中没有短信，等待\n",
      "队列中没有短信，等待\n",
      "开始给98765433发送短信，整个过程大概1-2秒钟\n",
      "手机号：98765433 短信发送成功！\n",
      "队列中没有短信，等待\n",
      "开始给4252452345发送短信，整个过程大概1-2秒钟\n",
      "手机号：4252452345 短信发送失败，等待重试！\n",
      "开始给46345643563发送短信，整个过程大概1-2秒钟\n",
      "手机号：46345643563 短信发送失败，等待重试！\n",
      "开始给345657456746发送短信，整个过程大概1-2秒钟\n",
      "手机号：345657456746 短信发送成功！\n",
      "开始给2523452345345发送短信，整个过程大概1-2秒钟\n",
      "手机号：2523452345345 短信发送失败，等待重试！\n",
      "开始给2435234645563发送短信，整个过程大概1-2秒钟\n",
      "手机号：2435234645563 短信发送失败，等待重试！\n",
      "开始给645656411345发送短信，整个过程大概1-2秒钟\n",
      "手机号：645656411345 短信发送失败，等待重试！\n",
      "开始给68796789558发送短信，整个过程大概1-2秒钟\n",
      "手机号：68796789558 短信发送失败，等待重试！\n",
      "开始给4252452345发送短信，整个过程大概1-2秒钟\n",
      "手机号：4252452345 短信发送成功！\n",
      "开始给46345643563发送短信，整个过程大概1-2秒钟\n",
      "手机号：46345643563 短信发送失败，等待重试！\n",
      "开始给2523452345345发送短信，整个过程大概1-2秒钟\n",
      "手机号：2523452345345 短信发送失败，等待重试！\n",
      "开始给2435234645563发送短信，整个过程大概1-2秒钟\n",
      "手机号：2435234645563 短信发送失败，等待重试！\n",
      "开始给645656411345发送短信，整个过程大概1-2秒钟\n",
      "手机号：645656411345 短信发送成功！\n",
      "开始给68796789558发送短信，整个过程大概1-2秒钟\n",
      "手机号：68796789558 短信发送成功！\n",
      "开始给46345643563发送短信，整个过程大概1-2秒钟\n",
      "手机号：46345643563 短信发送失败，等待重试！\n",
      "开始给2523452345345发送短信，整个过程大概1-2秒钟\n",
      "手机号：2523452345345 短信发送成功！\n",
      "开始给2435234645563发送短信，整个过程大概1-2秒钟\n",
      "手机号：2435234645563 短信发送失败，等待重试！\n",
      "开始给46345643563发送短信，整个过程大概1-2秒钟\n",
      "手机号：46345643563 短信发送失败，等待重试！\n",
      "重试超过3次，放弃手机号：46345643563\n",
      "开始给2435234645563发送短信，整个过程大概1-2秒钟\n",
      "手机号：2435234645563 短信发送成功！\n",
      "队列中没有短信，等待\n"
     ]
    },
    {
     "ename": "KeyboardInterrupt",
     "evalue": "",
     "output_type": "error",
     "traceback": [
      "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m",
      "\u001b[0;31mKeyboardInterrupt\u001b[0m                         Traceback (most recent call last)",
      "\u001b[0;32m<ipython-input-6-9a46c55e64a8>\u001b[0m in \u001b[0;36m<module>\u001b[0;34m()\u001b[0m\n\u001b[0;32m----> 1\u001b[0;31m \u001b[0mread_wait_queue\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m",
      "\u001b[0;32m<ipython-input-5-258de825f31c>\u001b[0m in \u001b[0;36mread_wait_queue\u001b[0;34m()\u001b[0m\n\u001b[1;32m      6\u001b[0m         \u001b[0;32mif\u001b[0m \u001b[0;32mnot\u001b[0m \u001b[0mphone_info_bytes\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m      7\u001b[0m             \u001b[0mprint\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m'队列中没有短信，等待'\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m----> 8\u001b[0;31m             \u001b[0mtime\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0msleep\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;36m10\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m      9\u001b[0m             \u001b[0;32mcontinue\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m     10\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n",
      "\u001b[0;31mKeyboardInterrupt\u001b[0m: "
     ]
    }
   ],
   "source": [
    "read_wait_queue()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 集合——去重、多条件查询"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
    "def register(account, password):\n",
    "    if client.sadd('web:account', account):\n",
    "        print('注册成功！')\n",
    "        return\n",
    "    print('账号已经被人注册了！')\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 8,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "注册成功！\n"
     ]
    }
   ],
   "source": [
    "register('kingname', 123456)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 9,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "注册成功！\n"
     ]
    }
   ],
   "source": [
    "register('boy', 987654)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 10,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "账号已经被人注册了！\n"
     ]
    }
   ],
   "source": [
    "register('kingname', 5534354)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 11,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "6"
      ]
     },
     "execution_count": 11,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "# 使用集合实现多条件筛选\n",
    "\n",
    "# 初始化数据\n",
    "\n",
    "math = [\n",
    "    '王晓一',\n",
    "    '张小二',\n",
    "    '刘小三',\n",
    "    '钱小七',\n",
    "    '李小八',\n",
    "    '周小九'\n",
    "]\n",
    "\n",
    "\n",
    "computer = [\n",
    "    '王晓一',\n",
    "    '刘小三',\n",
    "    '马小时',\n",
    "    '朱小五',\n",
    "    '李小八',\n",
    "    '周小九'\n",
    "]\n",
    "\n",
    "\n",
    "history = [\n",
    "    '王晓一',\n",
    "    '刘小三',\n",
    "    '马小时',\n",
    "    '朱小五',\n",
    "    '钱小七',\n",
    "    '李小八',\n",
    "]\n",
    "\n",
    "english = [\n",
    "    '张小二',\n",
    "    '刘小三',\n",
    "    '马小时',\n",
    "    '朱小五',\n",
    "    '李小八',\n",
    "    '周小九'\n",
    "]\n",
    "\n",
    "client.sadd('math', *math)\n",
    "client.sadd('english', *english)\n",
    "client.sadd('history', *history)\n",
    "client.sadd('computer', *computer)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 12,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "钱小七\n",
      "刘小三\n",
      "王晓一\n",
      "李小八\n"
     ]
    }
   ],
   "source": [
    "# 同时上数学和历史的人\n",
    "\n",
    "student_list = client.sinter('math', 'history')\n",
    "for student in student_list:\n",
    "    print(student.decode())"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 13,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "刘小三\n",
      "李小八\n"
     ]
    }
   ],
   "source": [
    "# 同时上数学、计算机、历史和英语的人\n",
    "\n",
    "student_list = client.sinter('math', 'history', 'computer', 'english')\n",
    "for student in student_list:\n",
    "    print(student.decode())"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 14,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "钱小七\n",
      "张小二\n"
     ]
    }
   ],
   "source": [
    "# 上数学没上计算机的人\n",
    "\n",
    "student_list = client.sdiff('math', 'computer')\n",
    "for student in student_list:\n",
    "    print(student.decode())"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "![读者交流QQ群](https://kingname-1257411235.cos.ap-chengdu.myqcloud.com/2019-02-16-09-59-56.png)\n",
    "![微信公众号](https://kingname-1257411235.cos.ap-chengdu.myqcloud.com/wechatplatform.jpg)\n",
    "![](https://kingname-1257411235.cos.ap-chengdu.myqcloud.com/2019-03-03-20-47-47.png)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": []
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.6.8"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 2
}
